/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
 * Description: Hmfs-tools encoding
 */

#include "hmfs_encoding.h"

#include <codecvt>
#include <cstring>
#include <locale>
#include <memory>
#include <sstream>
#include <unicode/casemap.h>
#include <unicode/uchar.h>
#include <unicode/unistr.h>
#include <unicode/utf8.h>
#include <unordered_map>

#include "hmfs_fs.h"

namespace OHOS {
namespace Hmfs {
const uint8_t HMFS_ARRAY_SIZE = 1;

static const EncodingInfo g_hmfsEncodingMap[] = {
    {"utf8", HMFS_ENC_UTF8_12_1, 0}
};

static const std::unordered_map<std::string, uint16_t> g_encodingFlagsMap = {
    {"strict", 1}
};

std::u16string Utf8ToUtf16(const std::string &utf8Str)
{
    std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
    return convert.from_bytes(utf8Str);
}

std::string Utf16ToUtf8(const std::u16string &utf16Str)
{
    std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
    return convert.to_bytes(utf16Str);
}

int32_t EncodingStrToValue(std::string &encodingString, uint16_t &value)
{
    for (uint32_t i = 0; i < HMFS_ARRAY_SIZE; i++) {
        if (encodingString == g_hmfsEncodingMap[i].encodingName) {
            value = g_hmfsEncodingMap[i].encodingKey;
            return 0;
        }
    }
    return -1;
}

int32_t EncodingValueToStr(const uint16_t encodingVal, std::string &str)
{
    for (uint32_t i = 0; i < HMFS_ARRAY_SIZE; i++) {
        if (g_hmfsEncodingMap[i].encodingKey == encodingVal) {
            str = g_hmfsEncodingMap[i].encodingName;
            return 0;
        }
    }
    return -1;
}

uint16_t GetDefaultEncodingFlag(uint16_t encoding)
{
    for (uint32_t i = 0; i < HMFS_ARRAY_SIZE; i++) {
        if (g_hmfsEncodingMap[i].encodingKey == encoding) {
            return g_hmfsEncodingMap[i].initialFlags;
        }
    }
    return 0;
}

int32_t EncodingFlagStrToValue(std::string &flagsStr, uint16_t &flags)
{
    std::stringstream flagList(flagsStr);
    std::string flagStr;
    while (std::getline(flagList, flagStr, ',')) {
        bool negFlag = false;
        if (flagStr.find("no") == 0) {
            negFlag = true;
            flagStr.erase(0, strlen("no"));
        }

        auto it = g_encodingFlagsMap.find(flagStr);
        if (it == g_encodingFlagsMap.end()) {
            return -1;
        }

        if (negFlag) {
            HMFS_DEBUG("Sub %s", flagStr.c_str());
            flags &= ~it->second;
        } else {
            HMFS_DEBUG("Add %s", flagStr.c_str());
            flags |= it->second;
        }
    }
    return 0;
}

bool IsNeedEncoding(int32_t encoding)
{
    if (encoding == HMFS_ENC_UTF8_12_1) {
        return true;
    }
    return false;
}

int32_t CaseFold(const unsigned char *str, size_t len, unsigned char *dest, size_t destLen)
{
    if (str == nullptr || dest == nullptr || len == 0 || destLen == 0) {
        HMFS_DEBUG("Invalid input parameters");
        return -EINVAL;
    }

    // Allocate a buffer for the case-folded result
    UErrorCode errorCode = U_ZERO_ERROR;
    icu::UnicodeString input(reinterpret_cast<const char *>(str), len, "UTF-8");
    std::vector<char16_t> buffer(input.length());
    int32_t resultLength = icu::CaseMap::fold(U_FOLD_CASE_DEFAULT, input.getBuffer(), input.length(),
        buffer.data(), buffer.size(), nullptr, errorCode);
    if (U_FAILURE(errorCode)) {
        HMFS_DEBUG("Failed to case fold string: %s", u_errorName(errorCode));
        return -EINVAL;
    }

    // Convert the result to UTF-8
    icu::UnicodeString caseFolded;
    caseFolded.setTo(false, buffer.data(), resultLength);
    std::string utf8Result;
    caseFolded.toUTF8String(utf8Result);
    if (utf8Result.size() > destLen) {
        HMFS_DEBUG("Result exceeds destination buffer size");
        return -ENAMETOOLONG;
    }

    std::copy(utf8Result.begin(), utf8Result.end(), dest);
    return utf8Result.size();
}
} // namespace Hmfs
} // namespace OHOS